<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" charset="UTF-8">
    <script>
        class ExtendableProxy {
            constructor(obj, handler) {
                return new Proxy(obj, handler);
            }
        }
        //代理对象构造类
        class ObserverObject extends ExtendableProxy {
            constructor(obj, handler, objectOwningProperty) {
                super(obj, handler);
            }

            static createNewInternal(rawObject, owningProperty) {
                let proxiedObject = new ObserverObject(rawObject, new SubscribableHandler(owningProperty), owningProperty);
                return proxiedObject;
            }
        }
        // 定义handler拦截器
        class SubscribableHandler {
            constructor(owningProperty) {
            }

            get(target, property, receiver) {
                console.log(`Getting ${property}`);
                return Reflect.get(target, property, receiver);
            }

            set(target, property, newValue) {
                let ret = Reflect.set(target, property, newValue);
                console.log(`SubscribableHandler Setting ${property} to ${newValue}`);
                printLog(`SubscribableHandler Setting ${property} to ${newValue}`);
                return ret;
            }
        }
        // 原始父类
        class Balloon {
            constructor() {
                this.volume = 4;
                this.child = new Child();
            }
        }
        // 子类
        class Child {
            constructor() {
                this.name = '001';
            }
        }
        let proxiedObject = null;

        //创建代理对象
        const createWrapper = function() {
            proxiedObject = ObserverObject.createNewInternal(new Balloon(), null);
            printLog("初始创建代理对象");
        }

        //修改第一层简单属性
        const modifyFirstAttr = function() {
            clearResult();
            proxiedObject.volume = 9;
        }

        //修改第一层对象属性
        const modifyFirstObjectAttr = function() {
            clearResult();
            let obj = new Child();
            obj.name = '002';
            proxiedObject.child = obj;
        }

        //修改第二层属性
        const modifySecondAttr = function() {
            clearResult();
            proxiedObject.child.name = '003';
        }

        //打印结果
        const printLog = function(str) {
            let div = document.getElementById('result');
            div.innerHTML = str;
            div.innerHTML += "<br/>";
            div.innerHTML += `proxiedObject = ${JSON.stringify(proxiedObject)}`;
        }

        const clearResult = function() {
            document.getElementById('result').innerHTML = '';
        }
    </script>
    <style type="text/css">
        body {
            text-align: center;
            font-family: 宋体;
        }
        div {
            margin-top: 10px;
        }
        button {
            line-height: 30px;
        }
    </style>
</head>
<body>
<div>JavaScript语言特性：Proxy代理对象原理</div>
<div>
    <button onclick="createWrapper()">创建代理对象ObserverObject</button>
</div>
<div>
    <button onclick="modifyFirstAttr()">修改第一层属性ObserverObject.volume = 9 会触发拦截</button>
</div>
<div>
    <button onclick="modifyFirstObjectAttr()">修改第一层属性ObserverObject.child会触发拦截</button>
</div>
<div>
    <button onclick="modifySecondAttr()">修改第二层属性ObserverObject.child.name不会触发拦截</button>
</div>
<div id="result"></div>
</body>
</html>